// 正则
// 匹配属性 id="app" id='app' id=app
const attribute = /^\s*([^\s"'<>\/=]+)(?:\s*(=)\s*(?:"([^"]*)"+|'([^']*)'+|([^\s"'=<>`]+)))?/;
// 匹配标签名 <my-comp></my-comp>
const ncname = `[a-zA-Z_][\\-\\.0-9_a-zA-Z]*`;
// 匹配 <my:comp></my:comp>
const qnameCapture = `((?:${ncname}\\:)?${ncname})`;
// 匹配开始标签 <div
const startTagOpen = new RegExp(`^<${qnameCapture}`);
// 匹配单标签结束 > />
const startTagClose = /^\s*(\/?)>/;
// 匹配结束标签 </div>
const endTag = new RegExp(`^<\\/${qnameCapture}[^>]*>`);

export function parseHtml(html) {
  const stack = [];
  let root, currentParent;
  // 不停解析html 直到html为空
  while (html) {
    let textEnd = html.indexOf("<");
    // 找到开始位置
    if (textEnd === 0) {
      //开始标签
      const startTagMatch = parseStartTag();
      if (startTagMatch) {
        //存在startTagMatch 执行start方法 传入 tagName attrs
        start(startTagMatch.tagName, startTagMatch.attrs);
        continue; // 匹配到开始标签 跳过 进入下次循环
      }
      // 结束标签
      const endTagMatch = html.match(endTag);
      if (endTagMatch) {
        //存在endTagMatch
        advance(endTagMatch[0].length);
        end(endTagMatch[1]);
        continue; // 匹配到结尾标签 跳过 进入下次循环
      }
    }
    let text;
    if (textEnd >= 0) {
      // 大于等于0 则是文本标签
      text = html.substring(0, textEnd);
    }

    if (text) {
      advance(text.length);
      chars(text);
    }
  }
  // 截取字符串方法
  function advance(n) {
    html = html.substring(n);
  }

  function parseStartTag() {
    const start = html.match(startTagOpen);
    if (start) {
      const match = {
        tagName: start[1],
        attrs: [],
      };
      //截取字符串
      advance(start[0].length);
      // 定义结束标签及属性
      let end, attr;
      // 未匹配到结束标签 并且 有属性
      while (
        !(end = html.match(startTagClose)) &&
        (attr = html.match(attribute))
      ) {
        // 解析属性
        match.attrs.push({
          name: attr[1],
          value: attr[3] || attr[4] || attr[5],
        });
        advance(attr[0].length);
      }
      if (end) {
        // 去掉'>'
        advance(end[0].length);
        return match;
      }
    }
  }

  function start(tag, attrs) {
    let element = createASTElement(tag, attrs);
    if (!root) {
      root = element;
    }
    // 保存element
    currentParent = element;
    stack.push(element);
  }
  function end(tag) {
    const element = stack.pop();
    currentParent = stack[stack.length - 1];
    if (currentParent) {
      //存在父级
      element.parent = currentParent;
      currentParent.children.push(element);
    }
  }

  function chars(text) {
    text = text.trim(); // 去空格
    if (text.length > 0) {
      currentParent.children.push({
        type: 3,
        text,
      });
    }
  }

  return root;
}

// 创建元素ast
function createASTElement(tag, attrs, parent) {
  return {
    type: 1,
    tag,
    attrs,
    parent: null,
    children: [],
  };
}
